package com.dynamic.mybatis.web.security;


import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import com.dynamic.mybatis.core.metadata.DynamicConfiguration;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.session.DynamicSqlSessionTemplate;
import com.dynamic.mybatis.core.toolkit.StringUtils;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.util.DigestUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

public class SecurityParameterInterceptHandler {

    public static final String secret = "!FAFSDFD";
    public static final String session_context = "_session_context_";
    public static final String ts = "_ts_";
    public DynamicConfiguration configuration;
    MessageDigest md5;
    DynamicSqlSessionTemplate dynamicSqlSessionTemplate;
    //用户私有变量 key md5(jwt token)  value 回话参数
    Cache<String,SecurityParameter> securityParameter = Caffeine.newBuilder()
            .expireAfterAccess(30, TimeUnit.MINUTES)
            .removalListener((k,v,removalCause)->{
                System.out.println("caffeine expired. "+k+"   "+v+"  "+removalCause);
            })
            .build();

    public SecurityParameterInterceptHandler(DynamicSqlSessionTemplate dynamicSqlSessionTemplate) {
        this.dynamicSqlSessionTemplate = dynamicSqlSessionTemplate;
        this.configuration = (DynamicConfiguration) dynamicSqlSessionTemplate.getSqlSession().getConfiguration();
/*        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }*/
    }
    public void setSecurityParameter(String namespace,String token,Object parameter) {
        securityParameter.put(getSecurityParameterKey(namespace,token),new SecurityParameter(parameter));
    }

    public String getSecurityParameterKey(String namespace,String token){
        return DigestUtils.md5DigestAsHex((Objects.toString(namespace,"")+token).getBytes());
       // return new String(md5.digest((Objects.toString(namespace,"")+token).getBytes()));
    }


    public Object getSecurityParameter(String namespace,String token){
        if(StringUtils.isEmpty(token)){
            return null;
        }
        //获取token对应的本地缓存
        String key = getSecurityParameterKey(namespace,token);
        SecurityParameter parameter = securityParameter.getIfPresent(key);
        Object param = null;
        if(parameter != null){
            parameter.setDateTime(System.currentTimeMillis());
            securityParameter.put(key,parameter);
            param =   parameter.getParameter();
        }else {
            //验证token
            verifyToken(token);
        }
        return param;
    }

    public static String generateToken(Map<String,Object> payload){
        payload.put(ts,System.currentTimeMillis());
        return  JWT.create()
                .withClaim(session_context, JSON.toJSONString(payload))
                .sign(Algorithm.HMAC256(secret)); //签名 相当于秘钥
    }

    public Object getTokenParameter(String token){
        DecodedJWT decodedJWT = verifyToken(token);
        String payload =  decodedJWT.getClaim(session_context).asString();
        return  JSON.parseObject(payload);
    }

    public DecodedJWT verifyToken(String token){
        Verification verification = JWT.require(Algorithm.HMAC256(secret));
        return  verification.build().verify(token);
    }


  class  SecurityParameter{
       public SecurityParameter(Object parameter) {
           this.parameter = parameter;
           this.dateTime = System.currentTimeMillis();
       }

        private Object parameter;
        private long dateTime;//最后一次访问时间

       public Object getParameter() {
           return parameter;
       }

       public void setParameter(Object parameter) {
           this.parameter = parameter;
       }

       public long getDateTime() {
           return dateTime;
       }

       public void setDateTime(long dateTime) {
           this.dateTime = dateTime;
       }
   }


    public static void main(String[] args) {
        String secret = "!FAFSDFD";
        String secret1 = "!FAFSDFD";
        Map<String,Object> payload = new HashMap<>();
        payload.put("userId", 123456); //payload
        payload.put("username", "zhangSan");
        String sign = JWT.create()
                .withPayload(payload)
                .sign(Algorithm.HMAC256(secret)); //签名 相当于秘钥
        System.out.println(sign);

        Verification verification = JWT.require(Algorithm.HMAC256(secret1));
        DecodedJWT decodedJWT = verification.build().verify(sign);
        Map<String,Object> param = new HashMap<>();
        decodedJWT.getClaims().forEach((k,v)->{
            param.put(k,decodedJWT.getClaim(k));
        });
    }
}
